﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;

public unsafe class arm : MonoBehaviour
{
    public static byte* vm_mem_buf;

    public static byte* vmpt_real(uint add)
    {
        return vm_mem_buf + add;
    }

    public static void println(string info)
    {
        UnityEngine.Debug.Log(info);
    }

    public static void logi(string info, object v1 = null, object v2 = null, object v3 = null, object v4 = null, object v5 = null, object v6 = null)
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    public static void logi(string info, object v1 , object v2, void* v3)
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    public static void logw(string info, object v1 = null, object v2 = null, object v3 = null, object v4 = null, object v5 = null, object v6 = null)
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    public static void loge(string info, object v1 = null, object v2 = null, object v3 = null, object v4 = null, object v5 = null, object v6 = null)
    {
        print(string.Format(info));
    }

    public static void usleep(uint time)
    {

    }

    public static void loginst(string info, uint v1 = 0, string v2 = "")
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    public static void println(string info, object v1 = null, object v2 = null)
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    public static void logsysc(string info, string v1 = "", string v2 = "")
    {
        print(string.Format(info + "   v1:{0}  v2:{1}", v1, v2));
    }

    // Start is called before the first frame update
    void Start()
    {
        byte[] a = new byte[5] { 1, 2, 3, 4, 5 };
        IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
        IntPtr p1 = ptr + 2;
        byte b = Marshal.ReadByte(p1);
    }

    // Update is called once per frame
    void Update()
    {

    }

    public static void time(time_t time)
    {

    }

    public static tm localtime(time_t time)
    {
        tm NewTime = new tm() { tm_year = (ushort)DateTime.Now.Year,
            tm_mday = (byte)DateTime.Now.Day,
            tm_hour = (byte)DateTime.Now.Hour,
            tm_min  = (byte)DateTime.Now.Minute,
            tm_mon  = (byte)DateTime.Now.Month ,
            tm_sec = (byte)DateTime.Now.Second,
        };
        return NewTime;
    }

    public static int powl(int x, uint y)
    {
        return (int)Mathf.Pow(x, y);
    }

    public static int powl(int x, int y)
    {
        return (int)Mathf.Pow(x, y);
    }

    public static int gettimeofday(timeval o, object v1)
    {
        o.tv_sec = System.Environment.TickCount;
        o.tv_usec = System.Environment.ProcessorCount;

        //Stopwatch sw = new Stopwatch();
        //sw.Start();
        //sw.Stop();

        //long microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
        
        return 0;
    }

    public static int clock_gettime(int v, timespec ts)
    {
        ts.tv_nsec = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
        ts.tv_sec = ts.tv_nsec / 1000;
        return 0;
    }

    public unsafe static byte* memcpy(void* dest, uint destIndex, byte[] src, uint srcIndex, uint len)
    {
        //IntPtr intPtr = getBytePtr(dest, destIndex);
        //Marshal.Copy(src, (int)srcIndex, intPtr, (int)len);
        //return dest;
        return memcpy((byte*)(dest), (byte*)getBytePtr<byte>(src), srcIndex, len);
    }

    public unsafe static byte* memcpy(byte[] dest, uint destIndex, byte[] src, uint srcIndex, uint len)
    {
        //IntPtr intPtr = getBytePtr(dest, destIndex);
        //Marshal.Copy(src, (int)srcIndex, intPtr, (int)len);
        //return dest;
        return memcpy((byte*)getBytePtr(dest,(int)destIndex), (byte*)getBytePtr<byte>(src), srcIndex, len);
    }

    public unsafe static byte* memcpy(byte* dest, uint destIndex, byte[] src, uint srcIndex, uint len)
    {
        return memcpy(dest+ destIndex, (byte*)getBytePtr<byte>(src), srcIndex, len);
    }

    public unsafe static void* memcpy(void* dest, string src,int len)
    {
        return memcpy(dest , (byte*)getBytePtr(src.ToCharArray ()),(uint) len);
    }

    public unsafe static byte* memcpy(byte[] dest, uint destIndex, void* src, uint len)
    {
        return (byte*)memcpy((void*)getBytePtr(dest , (int)destIndex), src, (uint)len);
    }

    public unsafe static byte* memcpy(byte* dest, byte* src,uint srcIndex, uint len)
    {
        return (byte*)memcpy(dest, (void*)(src+ srcIndex), (uint)len);
    }

    public unsafe static byte* memcpy(void* dest, byte[] src, uint srcIndex, uint len)
    {
        return (byte*)memcpy(dest, (void*)getBytePtr(src, (int)srcIndex), (uint)len);
    }

    public unsafe static byte* memcpy(sbyte* dest, char[] src, int len)
    {
        return (byte*)memcpy(dest ,(void *)getBytePtr( src), (uint)len);
    }

    public static void* memcpy(void* dst, void* src, uint size)
    {
        byte* psrc;
        byte* pdst;

        if (null == dst || null == src)
        {
            return null;
        }

        if ((src < dst) && (byte*)src + size > (byte*)dst) // 自后向前拷贝
        {
            psrc = (byte*)src + size - 1;
            pdst = (byte*)dst + size - 1;
            while (size-- != 0)
            {
                *pdst-- = *psrc--;
            }
        }
        else
        {
            psrc = (byte*)src;
            pdst = (byte*)dst;
            while (size-- != 0)
            {
                *pdst++ = *psrc++;
            }
        }

        return dst;
    }

    public static void* memmove(void* dest, void* src, uint n)
    {
        sbyte[] temp = new sbyte[n];
        int i;
        sbyte* d = (sbyte*)dest;
        sbyte* s = (sbyte*)src;

        for (i = 0; i < n; i++)
            temp[i] = s[i];
        for (i = 0; i < n; i++)
            d[i] = temp[i];

        return dest;
    }

    public static void memset(byte[] dest, uint destIndex, byte value, uint len)
    {
        for (int i = 0; i < len; i++)
        {
            dest[destIndex + i] = value;
        }
    }

    public static void memset(uint* dest , byte value, uint len)
    {
        for (int i = 0; i < len; i++)
        {
            dest[ i] = value;
        }
    }

    public static void memset(uint* dest, uint destIndex, byte value, uint len)
    {
        for (int i = 0; i < len; i++)
        {
            dest[destIndex + i] = value;
        }
    }

    public static void memset(sbyte* dest, byte value, uint len)
    {
        for (int i = 0; i < len; i++)
        {
            dest[i] = (sbyte)value;
        }
    }

    public static void memset(sbyte** dest, byte value, int len)
    {
        for (int i = 0; i < len; i++)
        {
            dest[i] = (sbyte*)value;
        }
    }

    public static void memset(object dest, uint destIndex, uint len)
    {
        //初始化
    }

    //public static void memset(void* dest, int destIndex, int len)
    //{
    //   //初始化
    //}

    /// <summary>
    /// 比较字节数组
    /// </summary>
    /// <param name="b1">字节数组1</param>
    /// <param name="b2">字节数组2</param>
    /// <returns>如果两个数组相同，返回0；如果数组1小于数组2，返回小于0的值；如果数组1大于数组2，返回大于0的值。</returns>
    public static int MemoryCompare(byte[] b1, byte[] b2)
    {
        int result = 0;
        if (b1.Length != b2.Length)
            result = b1.Length - b2.Length;
        else
        {
            for (int i = 0; i < b1.Length; i++)
            {
                if (b1[i] != b2[i])
                {
                    result = (int)(b1[i] - b2[i]);
                    break;
                }
            }
        }
        return result;
    }

    public static uint memcmp(byte[] dest, uint destIndex, byte[] src, uint srcIndex, uint len)
    {
        byte[] newDest = new byte[len];
        byte[] newSrc = new byte[len];
        for (int i = 0; i < len; i++)
        {
            newDest[i] = dest[destIndex + i];
            newSrc[i] = src[srcIndex + i];
        }
        return (uint)MemoryCompare(newDest, newSrc);
    }

    public static void memchr(byte[] dest, uint destIndex, byte value, uint len)
    {
        Debug.Log(string.Format("memchr"));
    }

    public static void snprintf(ref string dsmFullPath, string dest, string dir, string dsm, string fileName)
    {
        dsmFullPath = dir + "/" + dir + "/" + fileName;
    }

    public static void strcpy(sbyte* dest,sbyte* str,uint len=0)
    {
        string s = new string(str);
        
        for(int i=0;i<len; i++)
        {
            dest[i] = str[i];
        }
    }

    public static void strcat(sbyte* dest, sbyte* str, uint len = 0)
    {
        string s = new string(str);
        
        for (int i = 0; i < len; i++)
        {
            dest[i] = str[i];
            str[i] = 0;
        }
    }

    public static void free(object value)
    {
        UnityEngine.Debug.Log("free");
       // Marshal.FreeHGlobal(getMemoryPtr(value)); 
    }

    public static void free(void* value)
    {
        UnityEngine.Debug.Log("free");
        //Marshal.FreeHGlobal((IntPtr)value);
    }

    public static byte* malloc(uint len)
    {
        return (byte*)getBytePtr(new byte[len],0);
    }

    public static byte* malloc(int len)
    {
        return malloc((uint)len);
    }

    public static byte* malloc(long len)
    {
        return malloc((uint)len);
    }

    public static IntPtr getMemoryPtr(object o) // 获取引用类型的内存地址方法  
    {
        GCHandle h = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
        IntPtr addr = GCHandle.ToIntPtr(h);
        UnityEngine.Debug.Log("0x" + addr.ToString("X"));
        return addr;
    }

    public static bool isgraph(sbyte b)
    {
        return true;
    }

    public static uint write(IntPtr v, void* p, uint len)
    {
        memcpy( (void*)v, p, len);
        return (uint)(len);
    }

    public static uint read(FILE v, void* p, uint len)
    {
        byte[] date = new byte[len];
        v.Read(date, 0, (int)len);
        memcpy( p,0, date,0, len);
        return (uint)(len);
    }


    public static int F_OK = 0;
    public static int SEEK_SET = 0;
    public static int SEEK_CUR = 1;
    public static int SEEK_END = 2;

    public static int S_IRWXU = 0;
    public static int S_IRWXG = 1;
    public static int S_IRWXO = 2;

    public static int _O_RDONLY = 0x0000; // open for reading only
    public static int _O_WRONLY = 0x0001; // open for writing only
    public static int _O_RDWR = 0x0002; // open for reading and writing
    public static int _O_APPEND = 0x0008; // writes done at eof
    public static int _O_CREAT = 0x0100; // create and open file
    public static int O_RDONLY = _O_RDONLY;
    public static int O_WRONLY = _O_WRONLY;
    public static int O_RDWR = _O_RDWR;
    public static int O_APPEND = _O_APPEND;
    public static int O_CREAT = _O_CREAT;

    public static int lseek(FileStream v, int pos, int method)
    {
        if(method ==SEEK_SET)
            return (int)(v.Seek(pos, SeekOrigin.Begin));
        if (method == SEEK_CUR)
            return (int)(v.Seek(pos, SeekOrigin.Current));
        if (method == SEEK_END)
            return (int)(v.Seek(pos, SeekOrigin.End));
        return -1;
    }

    public static int remove(string str)
    {
        return 0;
    }

    public static int rename(string fullpathname_1, string fullpathname_2)
    {
        return 0;
    }

    public static int mkdir(string fullpathname,int v,int v2=0,int v3=0)
    {
        Directory.CreateDirectory(fullpathname);
        return 0;
    }

    public static int rmdir(string fullpathname)
    {
        Directory.Delete(fullpathname);
        return 0;
    }

    public  static int strcasecmp(string fullpathname, string sdcard_dir)
    {
        return fullpathname.Equals(sdcard_dir)?-1:0;
    }

    //public static IntPtr getBytePtr<T>(T[] data, uint index = 0) // 获取byte的内存地址方法  
    //{
    //  return   getBytePtr(data, (int)index);
    //}

    public static IntPtr getBytePtr<T>(T[] data, int index = 0) // 获取byte的内存地址方法  
    {
        IntPtr addr = Marshal.UnsafeAddrOfPinnedArrayElement<T>(data, index);
        return addr;
    }

    public static T GetObject<T>(byte[] date, uint index)
    {
        return Marshal.PtrToStructure<T>(Marshal.UnsafeAddrOfPinnedArrayElement(date, (int)index));
    }

    public static uint GetSize(object o)
    {
        if (o is byte[])
        {
            return (uint)((byte[])o).Length;
        }
      
        return (uint)Marshal.SizeOf(o.GetType());
    }

    public static int Sizeofc(void * c)
    {
        //int num = 0;
        //while (c != null && *c != 0)
        //{
        //    num++;
        //}
        //return num;
        return 1;
    }


    public static byte[] StringTobyte(string s)
    {
        return Encoding.Default.GetBytes(s.ToCharArray());
    }

    public static unsafe string String(byte[] date, uint index)
    {
        return new string ((sbyte *)(vm_mem_buf + index));
    }

    public static unsafe string String(sbyte* str)
    {
        return new string(str);
    }

    public static Dictionary<string,FILE> files=new Dictionary<string, FILE>();

    public static string FormatPathString(string path, char sep='/')
    {
        path = Application.streamingAssetsPath + "/" + path;
        path = path.Replace("//", "/");
        return path;
    }

    public static FILE fopen(string path, string mode)
    {
        path = FormatPathString(path);
        //(new FastZip()).ExtractZip(@path, @"C:\test\", "");
        //decompressFile(@path, Application.streamingAssetsPath + "/h");
        //System.IO.Compression.GZipStream gZipStream = new System.IO.Compression.GZipStream();
        //UnpackFiles(@path, @"C:\test");
        if (files.ContainsKey(path))
        {
            return files[path];
        }
        else
        {
            if (File.Exists(path))
            {
                FILE file = new FILE(path, FileMode.Open);
                files.Add(path, file);

                return file;
            }
            else
            {
                return null;
            }

        }
    }

    public static void fseek2(FILE file, uint offset, int seek)
    {
        file.Seek(offset-1, (SeekOrigin)seek);
        //file.brLength 
    }

    public static void fseek(FILE file, uint offset, int seek)
    {
        file.Seek(offset, (SeekOrigin)seek);
        //file.brLength 
    }

    public static uint fread(byte[] value, int offset, int cound, FILE file)
    {
        file.Read(value, offset-1, cound);
        return (uint)cound;
    }

    public static uint fread(out uint obj, int offset, int cound, FILE file)
    {
        byte[] b = new byte[cound];
        file.Read(b, offset-1, cound);
        obj =*((uint*)getBytePtr(b));
        return (uint)cound;
    }

    public static uint fread(out ushort obj, int offset, int cound, FILE file)
    {
        byte[] b = new byte[cound];
        file.Read(b, offset-1, cound);
        obj = *((ushort*)getBytePtr(b));
        return (uint)cound;
    }

    public static uint fread(out string obj, int offset, int cound, FILE file)
    {
        byte[] b = new byte[cound];
        file.Read(b, offset-1, cound);
        obj = new string ( ((sbyte*)getBytePtr(b)));
        return (uint)cound;
    }

    public static void fclose(FILE file)
    {
        //file.Flush();
        //file.Close();
    }

    //GB2312转换成unicode编码
    public static string GB2Unicode(string str)
    {
        string Hexs = "";
        string HH;
        Encoding GB = Encoding.GetEncoding("GB2312");
        Encoding unicode = Encoding.Unicode;
        byte[] GBBytes = GB.GetBytes(str);
        for (int i = 0; i < GBBytes.Length; i++)
        {
            HH = "%" + GBBytes[i].ToString("X");
            Hexs += HH;
        }
        return Hexs;
    }

    private static string Convert2Hex(string pstr)
    {
        if (pstr.Length == 2)
        {
            pstr = pstr.ToUpper();
            string hexstr = "0123456789ABCDEF";
            int cint = hexstr.IndexOf(pstr.Substring(0, 1)) * 16 + hexstr.IndexOf(pstr.Substring(1, 1));
            return cint.ToString();
        }
        else
        {
            return "";
        }
    }

    public static string UCS2ByteRev(sbyte* str)
    {
        sbyte temp;
        int i = 0;

        //char[] str = strS.ToCharArray();

        while (str[i] != 0 || str[i + 1] != 0)
        {
            temp = str[i];
            str[i] = str[i + 1];
            str[i + 1] = temp;
            i += 2;
        }

        return new string ( str);
    }
    public static uint UCS2_strlen(sbyte* txt)
    {
        int i = 0;

        while (txt[i]!=0 || txt[i + 1]!=0)
        {
            i += 2;
        }

        return (uint)i;
    }

    public static int access(string fullpathname, int f_OK)
    {
        //bool isTure = Directory.Exists(fullpathname);
        bool isTure = File.Exists(fullpathname);
        return isTure?0:-1;
    }

    public static FILE file1;
    public  static FILE open(string fullpathname, int new_mode, int v)
    {
        print ("Open:"+ fullpathname+ "   FileMode:" + ((FileMode)new_mode).ToString ());
        fullpathname = Application.streamingAssetsPath + "/" + fullpathname;
        file1 = new FILE(fullpathname, (FileMode.Open));
        return file1;
    }

    public static int close( FILE v)
    {
        if(v != null)
            v.Close();
        return 0;
    }

    public static sbyte * getStringPtr(string str)
    {
        int len = str.ToCharArray().Length;
        byte[] byteArrayOut =new byte[len];
        byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(str);
        Marshal.Copy(byteArray,0,getBytePtr( byteArrayOut), len);
        return (sbyte*)getBytePtr(byteArrayOut);

        //return (sbyte*)getBytePtr(str.ToCharArray ());
    }

    public static int _S_IFMT = 0xF000; // File type mask
    public static int _S_IFDIR = 0x4000; // Directory
public static int _S_IFCHR = 0x2000;// Character special
public static int _S_IFIFO = 0x1000;// Pipe
public static int _S_IFREG = 0x8000; // Regular
public static int _S_IREAD = 0x0100; // Read permission, owner
public static int _S_IWRITE = 0x0080; // Write permission, owner
public static int _S_IEXEC = 0x0040; // Execute/search permission, owner

    public static int S_IFDIR = _S_IFDIR;
    public static int S_IFCHR = _S_IFCHR;
public static int S_IFREG = _S_IFREG;
    public static int Stat(string path, stat s1)
    {
        FileStream file = fopen(path,"rb");
        path = Application.streamingAssetsPath + "/" + path;
        if (File.Exists(path))
            s1.st_mode = 1;
        else if (Directory.Exists(path))
            s1.st_mode = 2;
        if(file!=null)
        s1.st_size = (uint)file.Length;
        else
        {
            print("Not find file:"+ path);
        }
        return access(path ,0);
    }

    public static bool S_ISREG(ushort st_mode)// 是否是一个常规文件.
    {
        return st_mode == 1;
    }

    public static bool S_ISDIR(ushort st_mode)// 是否是一个目录
    {
        return st_mode == 2;
    }

    #region Decompress

   
    public static byte[] ungzip(ref byte[] src, uint srcLen, ref byte[] dst, ref uint dstLen)
    {
        ////UnpackFiles(src, @"C:\test");
        //// decompressFile(src, Application.streamingAssetsPath + "/h");
        //dst = DeflateDecompress(src);
        //dstLen = (uint)dst.Length;

        return dst;
    }

    #endregion


    public static dirent readdir(DIR pDir)
    {
        dirent dir = new dirent();
        dir.d_name = (sbyte*)pDir.handle.Handle;
        return dir;
    }

    public static uint closedir(DIR pDir)
    {

        return 0;
    }

    public static DIR opendir(string v)
    {
        FILE fileStream = new FILE(v, FileMode.Open);
        return new DIR(fileStream);
    }
}

public class FILE : FileStream
{
    public BinaryReader binaryReader;
    public long brLength;
    public FILE(string path, FileMode fileMode) :base(path, fileMode)
    {
        //binaryReader = new BinaryReader(this);
        //brLength = binaryReader.BaseStream.Length;
        //FileStream file = File.OpenRead(path);
    }

}

public class timeval
{
    internal int tv_sec;
    internal long tv_usec;
    public TimeSpan timeSpan;
    public timeval()
    {
        //timeSpan = TimeSpan.FromMilliseconds;
        //tv_sec = timeSpan.Seconds ;
        //tv_usec = timeSpan.Milliseconds;
        
    }
}

public class timespec
{
    internal long tv_sec;
    internal long tv_nsec;
}

public class stat
{
    public uint st_dev;
    public ushort st_ino;
    public  ushort st_mode;
    public short st_nlink;
    public short st_uid;
    public short st_gid;
    public uint st_rdev;
    public uint st_size;
    public long st_atime;
    public long st_mtime;
    public long st_ctime;
}

public class DIR
{
    public FILE handle;
    public DIR(FILE handle)
    {
        this. handle=  handle;
    }

    public static explicit operator uint(DIR v)
    {
        return (uint) v.handle.Handle;
    }

    public static explicit operator DIR(FILE v)
    {
        return new DIR(v);
    }
}

public unsafe class dirent
{
    public sbyte* d_name;
}

[StructLayoutAttribute(LayoutKind.Explicit, Pack = 1)]
public struct union
{
    [FieldOffset(0)]
    public ulong U;
    [FieldOffset(0)]
    public double F;
}

public class time_t
{

}

public class tm
{
    internal ushort tm_year;
    public byte tm_mon;
    public byte tm_mday;
    public byte tm_hour;
    public byte tm_min;
    public byte tm_sec;
}
